package org.teamswift.crow.rbac.common;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jdk.jfr.Label;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.shiro.SecurityUtils;
import org.hibernate.annotations.*;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import org.teamswift.crow.rbac.entity.CrowUser;
import org.teamswift.crow.rbac.enums.CrowRbacErrors;
import org.teamswift.crow.rest.annotation.I18N;
import org.teamswift.crow.rest.annotation.SystemGeneratedValue;
import org.teamswift.crow.rest.common.BaseCrowEntity;
import org.teamswift.crow.rest.common.ICrowEntity;
import org.teamswift.crow.rest.common.ICrowIO;
import org.teamswift.crow.rest.exception.impl.UserNotLoginException;
import org.teamswift.crow.rest.utils.CrowMessageUtil;

import javax.persistence.*;
import java.io.Serializable;

@EqualsAndHashCode(callSuper = true)
@MappedSuperclass
@Data
@FilterDefs({
        @FilterDef(
                name = "orgFilter",
                parameters = @ParamDef(name = "organization_id", type = "integer")
        )
})
@Filters({
        @Filter(name = "orgFilter", condition = "organization_id = :organization_id"),
})
@EntityListeners(AuditingEntityListener.class)
abstract public class CrowOrgLimitedEntity<ID extends Serializable, V extends ICrowIO> extends BaseCrowEntity<ID, V> {

    @Column(updatable = false, nullable = false)
    private Integer organizationId;

    @Column(updatable = false, nullable = false)
    @JsonIgnore
    @SystemGeneratedValue
    private Integer cbId;
    @Column(updatable = false, nullable = false)
    @JsonIgnore
    @SystemGeneratedValue
    private String cbName;
    @Transient
    @I18N("CreatedBy")
    private CrowUser createdBy;

    @JsonIgnore
    @SystemGeneratedValue
    private Integer mbId;
    @JsonIgnore
    @SystemGeneratedValue
    private String mbName;
    @Transient
    @I18N("ModifiedBy")
    private CrowUser modifiedBy;

    @PrePersist
    public void beforePersist() {
        CrowUser user = (CrowUser) SecurityUtils.getSubject().getPrincipal();
        if(user == null) {
            throw new UserNotLoginException(
                    CrowMessageUtil.error(CrowRbacErrors.EmptyCredential)
            );
        }

        setOrganizationId(user.getOrganizationId());
        setCbId(user.getId());
        setCbName(user.getName());
        setCreatedBy(user);
    }

    @PreUpdate
    public void beforeUpdate() {
        CrowUser user = (CrowUser) SecurityUtils.getSubject().getPrincipal();
        if(user == null) {
            throw new UserNotLoginException(
                    CrowMessageUtil.error(CrowRbacErrors.EmptyCredential)
            );
        }

        setMbId(user.getId());
        setMbName(user.getName());
        setModifiedBy(user);
    }

    public CrowUser getCreatedBy() {
        if(createdBy == null) {
            createdBy = new CrowUser();
            createdBy.setId(cbId);
            createdBy.setName(cbName);
        }
        return createdBy;
    }

    public CrowUser getModifiedBy() {
        if(modifiedBy == null) {
            modifiedBy = new CrowUser();
            modifiedBy.setId(mbId);
            modifiedBy.setName(mbName);
        }
        return modifiedBy;
    }

}
